package itsm.isperp.framework.web.request;

import itsm.isperp.framework.data.ObjectSqlSource;
import itsm.isperp.framework.data.domain.DataRequest;
import itsm.isperp.framework.data.domain.FilterRule;
import itsm.isperp.framework.utils.JsonBuilder;
import itsm.isperp.framework.web.domain.CountQuery;
import itsm.isperp.module.dto.project.ProjectDomain;

import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;

/**
 * <p>
 * JqGrid有客户端控件发送的请求。
 * </p>
 * page:"page", 表示请求页码的参数名称。<br />
 * rows:"rows" 表示请求行数的参数名称。<br />
 * sort: "sidx", 表示用于排序的列名的参数名称。<br />
 * order: "sord", 表示采用的排序方式的参数名称。<br />
 * search:"_search", 表示是否是搜索请求的参数名称。<br />
 * nd:"nd", 表示已经发送请求的次数的参数名称。<br />
 * id:"id", 表示当在编辑数据模块中发送数据时，使用的id的名称。<br />
 * oper:"oper", operation参数名称 。<br />
 * editoper:"edit", 当在edit模式中提交数据时，操作的名称 。<br />
 * addoper:"add", 当在add模式中提交数据时，操作的名称。<br />
 * deloper:"del", / 当在delete模式中提交数据时，操作的名称。<br />
 * subgridid:"id", 当点击以载入数据到子表时，传递的数据名称。<br />
 * npage: null, 。<br />
 * totalrows:"totalrows" 表示需从Server得到总共多少行数据的参数名称，参见jqGrid选项中的rowTotal
 * 
 * @author lizx
 * @date 2013-1-17
 * @version V1.0
 * @version V1.1 增加AddRule方法
 */
/**
 * @author lizx
 * 
 */
public class JqGridRequest implements ObjectSqlSource, DataRequest {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3558298206599539748L;

	/**
	 * 表示是否进行查询
	 */
	private boolean _serarch;
	/**
	 * 表示已经发送请求的次数
	 */
	private String nd;
	/**
	 * 表示请求行数的参数名称
	 */
	private int rows = 0;
	/**
	 * 表示请求页码的参数名称。
	 */
	private int page = 1;
	/**
	 * 表示用于排序的列名的参数名称。如 name asc,code desc,tel desc或者accout
	 * 
	 * 在实际中，如果存在行分组，那么会存在name asc,code desc；如果点击列则只会有accout
	 */
	private String[] sidx;
	/**
	 * 表示采用的排序方式的参数名称。
	 */
	private String sord;
	/**
	 * 查询列
	 */
	private String searchField;
	/**
	 * 查询的字符串
	 */
	private String searchString;

	/**
	 * only inner join
	 */
	private String joinString;
	/**
	 *  
	 */
	private String groupBy;

	/**
	 * 查询的操作方式
	 */
	private String searchOper;
	/**
	 * 过滤器
	 */
	private String filters;

	private String oper;

	private String[] selectColumns;

	private boolean pageable;

	private boolean onlyQueryCount;

	private ProjectDomain projectDomain;

	private CountQuery countQuery;

	private String queryPath;

	private boolean notMenu;

	public boolean isNotMenu() {
		return notMenu;
	}

	public void setNotMenu(boolean notMenu) {
		this.notMenu = notMenu;
	}

	/**
	 * 构造一个请求
	 */
	public JqGridRequest() {
	}

	/**
	 * 通过一个http请求构造
	 * 
	 * @param request
	 *            http请求
	 */
	public JqGridRequest(HttpServletRequest request) {
	}

	/**
	 * 通过一个http请求构造
	 * 
	 * @param request
	 *            http请求
	 */
	public JqGridRequest(Pageable pageable) {
		this.rows = pageable.getPageSize();
		this.page = pageable.getPageNumber();
		this.pageable = true;
	}

	public String getQueryPath() {
		return queryPath;
	}

	public void setQueryPath(String queryPath) {
		this.queryPath = queryPath;
	}

	public CountQuery getCountQuery() {
		return countQuery;
	}

	public void setCountQuery(CountQuery countQuery) {
		this.countQuery = countQuery;
	}

	public boolean is_serarch() {
		return _serarch;
	}

	public void set_serarch(boolean _serarch) {
		this._serarch = _serarch;
	}

	public String getNd() {
		return nd;
	}

	public void setNd(String nd) {
		this.nd = nd;
	}

	/**
	 * 获取查询的行数
	 * 
	 * @return 查询的行数
	 */
	public int getRows() {
		return rows;
	}

	/**
	 * 设置需要发挥的行数，此设定有在不分页请求中有效
	 * 
	 * @param rows
	 */
	public void setRows(int rows) {
		this.rows = rows;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public String[] getSidx() {
		return sidx;
	}

	public void setSidx(String[] sidx) {
		this.sidx = sidx;
	}

	public String getSord() {
		return sord;
	}

	public void setSord(String sord) {
		this.sord = sord;
	}

	public String getSearchField() {
		return searchField;
	}

	public void setSearchField(String searchField) {
		this.searchField = searchField;
	}

	public String getSearchString() {
		return searchString;
	}

	public void setSearchString(String searchString) {
		this.searchString = searchString;
	}

	public String getJoinString() {
		return joinString;
	}

	public void setJoinString(String joinString) {
		this.joinString = joinString;
	}

	public String getSearchOper() {
		return searchOper;
	}

	public void setSearchOper(String searchOper) {
		this.searchOper = searchOper;
	}

	public String getFilters() {
		return filters;
	}

	public void setFilters(String filters) {
		this.filters = filters;
	}

	public String getOper() {
		return oper;
	}

	public void setOper(String oper) {
		this.oper = oper;
	}

	/**
	 * 获取JqGrid的过滤器实体{@link JqGridFilter}
	 * 
	 * @return JqGrid的过滤器实体
	 */
	@Override
	public JqGridFilter getFilter() {
		return JsonBuilder.buildNormalBinder().fromJson(this.filters,
				JqGridFilter.class);
	}

	/**
	 * 新增一个过滤条件，将会重设filters的值
	 * 
	 * @param rule
	 *            过滤条件
	 */
	@Override
	public DataRequest addFilterRule(FilterRule rule) {
		JqGridFilter filter = null;
		if (this.filters == null) {
			filter = new JqGridFilter();
			filter.setGroupOp("AND");
			filter.setRules(new ArrayList<JqGridFilterRule>());
		} else {
			filter = this.getFilter();
		}

		filter.addRule(rule);
		this.filters = JsonBuilder.buildNormalBinder().toJson(filter);

		return this;
	}

	/**
	 * 获取排序使用sql语句
	 * 
	 * @return 排序使用sql语句
	 */
	public String getOrderSql() {

		if (sidx != null) {
			StringBuilder sb = new StringBuilder();
			int len = sidx.length;
			for (int i = 0; i < len; i++) {
				makeSidxOrderStr(sidx[i], sb, ",");
			}
			String s = StringUtils.substringBeforeLast(sb.toString(), ",");
			if ("".equals(s.trim())) {
				return "";
			}
			return " ORDER BY  " + s;
		}

		return "";
	}

	private void makeSidxOrderStr(final String str, StringBuilder sb,
			String split) {
		if (StringUtils.isEmpty(str)) {
			return;
		}
		if (str.indexOf(" ") > 0) {
			sb.append(" ")
					.append(itsm.isperp.framework.utils.StringUtils
							.underscore(str)).append(split);
		} else {
			sb.append(" ")
					.append(itsm.isperp.framework.utils.StringUtils
							.underscore(str)).append(" ")
					.append(this.sord == null ? "" : this.sord).append(split);
		}
	}

	/**
	 * 获取过滤器的sql语句
	 */
	@Override
	public String getSql() {
		JqGridFilter filter = this.getFilter();
		StringBuilder sb = new StringBuilder();
		if (filter != null) {
			sb.append(filter.getSql());
		}
		return sb.append(this.getOrderSql()).toString();
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("JqGridRequest [");
		if (nd != null) {
			builder.append("nd=");
			builder.append(nd);
			builder.append(", ");
		}
		builder.append("rows=");
		builder.append(rows);
		builder.append(", page=");
		builder.append(page);
		builder.append(", ");
		if (sidx != null) {
			builder.append("sidx=");
			builder.append(sidx);
			builder.append(", ");
		}
		if (sord != null) {
			builder.append("sord=");
			builder.append(sord);
			builder.append(", ");
		}
		if (searchField != null) {
			builder.append("searchField=");
			builder.append(searchField);
			builder.append(", ");
		}
		if (searchString != null) {
			builder.append("searchString=");
			builder.append(searchString);
			builder.append(", ");
		}
		if (searchOper != null) {
			builder.append("searchOper=");
			builder.append(searchOper);
			builder.append(", ");
		}
		if (filters != null) {
			builder.append("filters=");
			builder.append(filters);
		}
		builder.append("]");
		return builder.toString();
	}

	@Override
	public int getPageNumber() {
		return this.page;
	}

	@Override
	public int getPageSize() {
		return this.rows;
	}

	@Override
	public int getOffset() {
		return page == 0 ? 0 : (page - 1) * rows;
	}

	@Override
	public Sort getSort() {
		if (this.sidx != null && this.sidx.length > 0) {
			Order[] orders = new Order[this.sidx.length];
			int len = sidx.length;
			for (int i = 0; i < len; i++) {
				makeOrder(
						itsm.isperp.framework.utils.StringUtils
								.underscore(sidx[i]),
						i, orders);
			}

			return new Sort(orders);
		}
		return null;
	}

	private void makeOrder(String str, int i, Order[] orders) {
		if (str.indexOf(" ") > 0) {
			String[] strs = str.trim().split(" ");
			if ("asc".equalsIgnoreCase(strs[strs.length - 1])) {
				orders[i] = new Order(Direction.ASC, strs[0]);
			} else {
				orders[i] = new Order(Direction.DESC, strs[0]);
			}
		} else {

			if (StringUtils.isEmpty(this.sord)
					|| "asc".equalsIgnoreCase(this.sord)) {
				orders[i] = new Order(Direction.ASC, str);
			} else {
				orders[i] = new Order(Direction.DESC, str);
			}
		}
	}

	@Override
	public DataRequest setSort(String sidx, Direction sord) {
		this.sidx = new String[1];
		this.sidx[0] = sidx;
		this.sord = sord == null ? null : sord.name();
		return this;
	}

	public DataRequest addSidx(String sidx) {
		if (this.sidx == null) {
			this.sidx = new String[1];
			this.sidx[0] = sidx;
		} else {
			int len = this.sidx.length;
			String[] t = new String[len + 1];
			System.arraycopy(this.sidx, 0, t, 0, len);
			this.sidx = t;
			this.sidx[len] = sidx;
		}

		return this;
	}

	@Override
	public DataRequest addFilterRule(String field, JqGridFilterRuleOp op,
			String data) {
		this.addFilterRule(new JqGridFilterRule(field, op, data));
		return this;
	}

	@Override
	public String getSelectColumnsString() {
		// 优先使用自定义的列
		if (this.selectColumns == null || this.selectColumns.length == 0) {
			return " * ";
		}
		String fields = " " + selectColumns[0];
		for (int i = 1; i < selectColumns.length; i++) {
			String s = selectColumns[i];

			if (StringUtils.isNotBlank(s))
				if (s.trim().indexOf(" ") > 0)
					fields += "," + s;
				else
					fields += ","
							+ itsm.isperp.framework.utils.StringUtils
									.underscore(s);
		}
		return fields + " ";
	}

	@Override
	public String[] getSelectColumns() {
		return this.selectColumns;
	}

	@Override
	public DataRequest setSelectColumns(String... columns) {
		this.selectColumns = columns;
		return this;
	}

	@Override
	public DataRequest addSelectColumns(String columns) {
		addSelectColumns(columns, 0);

		return this;
	}

	@Override
	public DataRequest addSelectColumnsInFirst(String columns) {
		addSelectColumns(columns, 1);

		return this;
	}

	private DataRequest addSelectColumns(String columns, int index) {
		if (this.selectColumns == null) {
			return setSelectColumns(columns);
		}

		int len = this.selectColumns.length;
		String[] t = new String[len + 1];
		System.arraycopy(this.selectColumns, 0, t, 0, len);
		this.selectColumns = t;

		this.selectColumns[index == 0 ? len : 0] = columns;

		return this;
	}

	@Override
	public DataRequest isPageable(boolean isPageable) {
		this.pageable = isPageable;
		return this;
	}

	@Override
	public boolean isPageable() {
		return this.pageable;
	}

	public void setPageable(boolean pageable) {
		this.pageable = pageable;
	}

	@Override
	public String getGroupBy() {
		return groupBy;
	}

	@Override
	public DataRequest setGroupBy(String groupBy) {
		this.groupBy = groupBy;
		return this;
	}

	@Override
	public Pageable next() {
		JqGridRequest thisClone = null;
		try {
			thisClone = (JqGridRequest) this.clone();
		} catch (CloneNotSupportedException e) {
			return null;
		}
		thisClone.setPage(this.getPage() + 1);
		return thisClone;
	}

	@Override
	public Pageable previousOrFirst() {
		if (hasPrevious()) {
			JqGridRequest thisClone = null;
			try {
				thisClone = (JqGridRequest) this.clone();
			} catch (CloneNotSupportedException e) {
				return null;
			}
			thisClone.setPage(this.getPage() - 1);
			return thisClone;
		}

		return this;
	}

	@Override
	public Pageable first() {
		JqGridRequest thisClone = null;
		try {
			thisClone = (JqGridRequest) this.clone();
		} catch (CloneNotSupportedException e) {
			return null;
		}
		thisClone.setPage(1);
		return thisClone;
	}

	@Override
	public boolean hasPrevious() {
		return this.page > 0;
	}

	/**
	 * 是否查询多个对象，如果为true则isPageable属性自动设置为false
	 * 
	 * @param b
	 */
	public void isQueryOne(boolean b) {
		if (b) {
			this.pageable = false;
			this.rows = 1;
		} else {
			this.rows = 15;
		}
	}

	public ProjectDomain getProjectDomain() {
		return projectDomain;
	}

	public void setProjectDomain(ProjectDomain projectDomain) {
		this.projectDomain = projectDomain;
	}

	public boolean isOnlyQueryCount() {
		return onlyQueryCount;
	}

	public void setOnlyQueryCount(boolean onlyQueryCount) {
		this.onlyQueryCount = onlyQueryCount;
	}

}
